/*
 * Unidata Platform
 * Copyright (c) 2013-2020, UNIDATA LLC, All rights reserved.
 *
 * Commercial License
 * This version of Unidata Platform is licensed commercially and is the appropriate option for the vast majority of use cases.
 *
 * Please see the Unidata Licensing page at: https://unidata-platform.com/license/
 * For clarification or additional options, please contact: info@unidata-platform.com
 * -------
 * Disclaimer:
 * -------
 * THIS SOFTWARE IS DISTRIBUTED "AS-IS" WITHOUT ANY WARRANTIES, CONDITIONS AND
 * REPRESENTATIONS WHETHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE
 * IMPLIED WARRANTIES AND CONDITIONS OF MERCHANTABILITY, MERCHANTABLE QUALITY,
 * FITNESS FOR A PARTICULAR PURPOSE, DURABILITY, NON-INFRINGEMENT, PERFORMANCE AND
 * THOSE ARISING BY STATUTE OR FROM CUSTOM OR USAGE OF TRADE OR COURSE OF DEALING.
 */
/**
 *
 */
package org.unidata.mdm.rest.v1.search.converter;

import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

import org.apache.commons.collections4.CollectionUtils;
import org.unidata.mdm.rest.v1.search.ro.SearchResultExtendedValueRO;
import org.unidata.mdm.rest.v1.search.ro.SearchResultHitFieldRO;
import org.unidata.mdm.rest.v1.search.ro.SearchResultHitRO;
import org.unidata.mdm.rest.v1.search.ro.SearchResultRO;
import org.unidata.mdm.search.dto.SearchResultDTO;
import org.unidata.mdm.search.dto.SearchResultHitDTO;
import org.unidata.mdm.search.dto.SearchResultHitFieldDTO;

/**
 * @author Mikhail Mikhailov
 */
public class SearchResultToRestSearchResultConverter {

    /**
     * Constructor.
     */
    private SearchResultToRestSearchResultConverter() {
        super();
    }

    /**
     * Converts search result to REST search result.
     *
     * @param result the result from the search service.
     * @return REST object
     */
    public static SearchResultRO convert(SearchResultDTO result) {

        if (result == null) {
            return null;
        }

        SearchResultRO ro = new SearchResultRO();

        ro.setFields(result.getFields());
        ro.setTotalCount(result.getTotalCount());
        ro.setMaxScore(result.getMaxScore());
        ro.setTotalCountLimit(result.getTotalCountLimit());

        convert(result.getHits(), ro.getHits(), result.getMaxScore());

        return ro;
    }

    /**
     * Hits -> hits conversion method.
     *
     * @param source    the source
     * @param target    the target
     */
    private static void convert(List<SearchResultHitDTO> source, List<SearchResultHitRO> target, Float maxScore) {

        for (SearchResultHitDTO hit : source) {

            SearchResultHitRO hitRO = new SearchResultHitRO(hit.getInternalId());
            for (SearchResultHitFieldDTO field : hit.getPreview().values()) {

                SearchResultHitFieldRO fieldRO = convert(field);
                if (Objects.isNull(fieldRO)) {
                    continue;
                }

                hitRO.getPreview().add(fieldRO);
            }

            hitRO.setSource(hit.getSource());
            if (maxScore == null || Float.isNaN(maxScore) || maxScore == 0) {
                hitRO.setScore(1f);
            } else {
                hitRO.setScore(Math.round(hit.getScore() / maxScore * 100) / 100f);
            }


            target.add(hitRO);
        }
    }

    private static SearchResultHitFieldRO convert(SearchResultHitFieldDTO field) {

        if (Objects.isNull(field)) {
            return null;
        }

        SearchResultHitFieldRO fieldRO;
        if (CollectionUtils.isNotEmpty(field.getExtendedValues())) {

            List<Object> displayValues = field.getExtendedValues().stream()
                    .map(r -> r.getDisplayValue() == null ? r.getValue() : r.getDisplayValue())
                    .collect(Collectors.toList());

            fieldRO = new SearchResultHitFieldRO(field.getField(), displayValues.get(0), displayValues);
        } else {
            fieldRO = new SearchResultHitFieldRO(field.getField(), field.getFirstValue(), field.getValues());
        }

        if (CollectionUtils.isNotEmpty(field.getExtendedValues())) {

            fieldRO.setExtendedValues(field.getExtendedValues().stream()
                    .map(r -> new SearchResultExtendedValueRO(r.getValue(), r.getDisplayValue(), r.getLinkedEtalonId()))
                    .collect(Collectors.toList()));
        } else if (CollectionUtils.isNotEmpty(field.getValues())) {

            fieldRO.setExtendedValues(field.getValues().stream()
                    .map(r -> new SearchResultExtendedValueRO(r, null, null))
                    .collect(Collectors.toList()));
        }

        return fieldRO;
    }
}
